const path = require('path')
const { src, dest, parallel, series, watch } = require('gulp')
const browserSync = require('browser-sync').create()
const plugins = require('gulp-load-plugins')()
const del = require('del')

// html 模板所需的信息
const data = {
  menus: [
    {
      name: 'Home',
      icon: 'aperture',
      link: 'index.html'
    },
    {
      name: 'Features',
      link: 'features.html'
    },
    {
      name: 'About',
      link: 'about.html'
    },
    {
      name: 'Contact',
      link: '#',
      children: [
        {
          name: 'Twitter',
          link: 'https://twitter.com/w_zce'
        },
        {
          name: 'About',
          link: 'https://weibo.com/zceme'
        },
        {
          name: 'divider'
        },
        {
          name: 'About',
          link: 'https://github.com/zce'
        }
      ]
    }
  ],
  pkg: require('./package.json'),
  date: new Date()
}

// 配置
let config = {
  src: 'src',
  tmp: 'temp',
  dist: 'dist',
  public: 'public',

  css: 'assets/styles/*.scss',
  js: 'assets/scripts/*.js',
  html: '*.html',
  image: 'assets/images/**',
  font: 'assets/fonts/**',

  data,
  port: parseInt(process.argv.find((x, i, arr) => arr[i-1] === '--port')) || 2080,
  open: process.argv.includes('--open'),
  production: !!process.argv.find(x => x === '--prod' || x === '--production')
}

// 各种构建任务

function lintJs () {
  return src(config.js, { base: config.src, cwd: config.src })
    .pipe(plugins.jshint({
      esversion: 6, // ES6
      asi: true // 不加分号
    }))
    .on('error', console.error)
    .pipe(plugins.jshint.reporter('default'))
    .pipe(plugins.jshint.reporter('fail'))
}

function lintCss () {
  return src(config.css, { base: config.src, cwd: config.src })
    .pipe(plugins.stylelint({
      reporters: [
        {formatter: 'string', console: true}
      ]
    }))
}

function compileCss () {
  return src(config.css, { base: config.src, cwd: config.src })
    .pipe(plugins.sass({ outputStyle: 'expanded' }))
    .pipe(dest(config.tmp))
}

function compileJs () {
  return src(config.js, { base: config.src, cwd: config.src })
    .pipe(plugins.babel({ presets: [require('@babel/preset-env')] }))
    .pipe(dest(config.tmp))
}

function compileHtml () {
   return src(config.html, { base: config.src, cwd: config.src })
    .pipe(plugins.swig({ data: config.data, cache: false }))
    .pipe(dest(config.tmp))
}

function server (baseDir, routes) {
  browserSync.init({
    files: baseDir[0].toString() + '/**', // 监听文件变化
    server: { baseDir, routes },
    // nofity: false, // 显示“已连接”等通知
    port: config.port,
    open: config.open // 自动打开浏览器
  })
}

function devServer () {
  // css, js, html 变化时重新编译
  watch(config.css, { cwd: config.src }, compileCss)
  watch(config.js, { cwd: config.src }, compileJs)
  watch(config.html, { cwd: config.src }, compileHtml)

  // 图片等资源变化时不编译, 仅刷新浏览器
  watch([ config.image, config.font ], { cwd: config.src }, browserSync.reload)
  watch('**', { cwd: config.public }, browserSync.reload)
  server([ config.tmp, config.src, config.public ], {
    '/node_modules': 'node_modules' // 开发用到的库
  })
}

function prodServer () {
  server([config.dist])
}

function useref () {
  // 这里用 path.join 而不是 cwd,
  // 否则 vendor.js, vendor.css 将不会输出到 dist/
  return src(path.join(config.tmp, config.html), { base: config.tmp })
    .pipe(plugins.useref({ searchPath: [config.tmp, '.'] }))
    .pipe(plugins.if(/\.js$/, plugins.uglify()))
    .pipe(plugins.if(/\.css$/, plugins.cleanCss()))
    .pipe(plugins.if(/\.html$/, plugins.htmlmin({
      collapseWhitespace: true,
      minifyCSS: true,
      minifyJS: true
    })))
    .pipe(dest(config.dist))
}

function minImage () {
  return src(config.image, { base: config.src, cwd: config.src })
    .pipe(plugins.imagemin())
    .pipe(dest(config.dist))
}

function minFont () {
  return src(config.font, { base: config.src, cwd: config.src })
    .pipe(plugins.imagemin())
    .pipe(dest(config.dist))
}

function copyPublic () {
  return src('**', { base: config.public, cwd: config.public })
    .pipe(dest(config.dist))
}

function deploy (done) {
  console.log('deploying to github pages...')
  done()
}

function clean () {
  return del([config.dist, config.tmp])
}

// 组合任务

const lint = parallel(lintJs, lintCss)
const compile = parallel(compileCss, compileJs, compileHtml)
const serve = series(compile, devServer)
const minify = series(compile, useref)
const build = series(
  clean,
  parallel(minify, minImage, minFont, copyPublic),
)
const start = series(build, prodServer)

module.exports = {
  lint,
  compile,
  serve, // --open, --port
  build, // --production, --prod
  start, // --open, --port
  deploy, // production, --prod
  clean
}
